package com.common.network;

import android.util.Log;

import com.common.annotations.PeRetrofit;
import com.common.network.body.ProgressResponseBody;
import com.common.network.help.BaseUrl;
import com.common.BuildConfig;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import dagger.Module;
import dagger.Provides;
import io.reactivex.schedulers.Schedulers;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

/**
 * author : Administrator
 * e-mail : 254419013@qq.com
 * time   : 2017/07/06
 * desc   :
 */
@Module
public class RetrofitModule {

    private static final String TAG = "RetrofitModule";

    //初始化的url
    private Object url;

    /**
     * 0:无进度的okhttp
     * 1:Response进度的okhttp
     * 2:Request进度的okhttp
     */
    private int okHttpType;

    private ProgressResponseBody.ProgressListener progressListener;

    private Converter.Factory factory;

    //baseUrl
    private static final Map<Integer, BaseUrl> baseUrlMap = new HashMap<>();

    //okHttpClient
    private static final Map<BaseUrl, OkHttpClient> okHttpClientMap = new HashMap<>();

    //retrofit
    private static final Map<OkHttpClient, Retrofit> retrofitMap = new HashMap<>();

    public RetrofitModule(Object url, int okHttpType, ProgressResponseBody.ProgressListener progressListener, Converter.Factory factory) {
        this.url = url;
        this.okHttpType = okHttpType;
        if (progressListener == null) {
            progressListener = new ProgressResponseBody.ProgressListener() {

                @Override
                public void update(long totalBytesRead, long contentLength, boolean isBytesRead) {

                }
            };
        }
        this.progressListener = progressListener;
        this.factory = factory;
    }

    @PeRetrofit
    @Provides
    Object createUrl() {
        return url;
    }

    @PeRetrofit
    @Provides
    int createOkHttpType() {
        return okHttpType;
    }

    @PeRetrofit
    @Provides
    ProgressResponseBody.ProgressListener createProgressResponseBody() {
        return progressListener;
    }

    @PeRetrofit
    @Provides
    Converter.Factory createConverterFactory() {
        return factory;
    }


    private BaseUrl createBaseUrl(Object url) {

        String baseUrlString = null;
        HttpUrl baseUrlHttpUrl = null;

        if (url instanceof String) {
            baseUrlString = (String) url;
            baseUrlHttpUrl = null;
        } else if (url instanceof HttpUrl) {
            baseUrlString = null;
            baseUrlHttpUrl = (HttpUrl) url;
        }

        //算出哈希值
        int result = baseUrlString != null ? baseUrlString.hashCode() : 0;
        result = 31 * result + (baseUrlHttpUrl != null ? baseUrlHttpUrl.hashCode() : 0);

        if (baseUrlMap.containsKey(result)) {
            if (BuildConfig.DEBUG) Log.d(TAG, "有包含BaseUrl -----------------");
            return baseUrlMap.get(result);
        } else {
            BaseUrl baseUrl = new BaseUrl(baseUrlString, baseUrlHttpUrl);
            if (BuildConfig.DEBUG) Log.d(TAG, "新建BaseUrl -----------------");
            baseUrlMap.put(baseUrl.hashCode(), baseUrl);
            return baseUrl;
        }

    }


    private OkHttpClient createOkHttpClient(BaseUrl baseUrl, int okHttpType, final ProgressResponseBody.ProgressListener progressListener) {

        if (okHttpClientMap.containsKey(baseUrl)) {
            if (BuildConfig.DEBUG) Log.d(TAG, "有包含OkHttpClient -----------------");
            return okHttpClientMap.get(baseUrl);
        }

        OkHttpClient okHttpClient;
        if (okHttpType == 0) {
            HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
            interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            Interceptor authorizationInterceptor = new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {

                    Request request = chain.request();
                    long t1 = System.nanoTime();
                    Log.d(TAG, String.format("Sending request %s on %s%n%s", request.url(),
                            chain.connection(), request.headers()));

                    Response response = chain.proceed(request);
                    long t2 = System.nanoTime();
                    Log.d(TAG, String.format("Received response for %s in %.1fms%n%s",
                            response.request().url(), (t2 - t1) / 1e6d, response.headers()));

                    return response;
                }
            };
            okHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(interceptor)//设置应用拦截器
                    .retryOnConnectionFailure(false) //错误重联
                    .connectTimeout(10, TimeUnit.SECONDS)//链接超时
                    .readTimeout(10, TimeUnit.SECONDS)//读取超时
                    .addNetworkInterceptor(authorizationInterceptor)//网络拦截器
                    .build();
        } else if (okHttpType == 1) {
            Interceptor authorizationInterceptor = new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {

                    Response originalResponse = chain.proceed(chain.request());
                    return originalResponse.newBuilder().body(new ProgressResponseBody(originalResponse.body(), progressListener)).build();

                }
            };
            okHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(authorizationInterceptor)//设置应用拦截器
                    .retryOnConnectionFailure(false) //错误重联
                    .connectTimeout(120, TimeUnit.MINUTES)//链接超时
                    .readTimeout(120, TimeUnit.MINUTES)//读取超时
                    .build();
        } else {
            okHttpClient = new OkHttpClient.Builder()
                    .retryOnConnectionFailure(false) //错误重联
                    .connectTimeout(120, TimeUnit.MINUTES)//链接超时
                    .readTimeout(120, TimeUnit.MINUTES)//读取超时
                    .build();
        }

        if (BuildConfig.DEBUG) Log.d(TAG, "新建OkHttpClient -----------------");
        okHttpClientMap.put(baseUrl, okHttpClient);
        return okHttpClient;
    }

    @PeRetrofit
    @Provides
    Retrofit createRetrofit(Object url, int okHttpType, ProgressResponseBody.ProgressListener progressListener, Converter.Factory factory) {

        BaseUrl baseUrl = createBaseUrl(url);
        if (BuildConfig.DEBUG) Log.d(TAG, "baseUrl = "+baseUrl.getBaseUrlString());
        OkHttpClient okHttpClient = createOkHttpClient(baseUrl, okHttpType, progressListener);

        if (okHttpClientMap.containsKey(baseUrl)) {
            if (retrofitMap.containsKey(okHttpClientMap.get(baseUrl))) {
                if (BuildConfig.DEBUG) Log.d(TAG, "有包含Retrofit -----------------");
                return retrofitMap.get(okHttpClientMap.get(baseUrl));
            }
        }
        Retrofit retrofit;
        if (baseUrl.getBaseUrlString() != null && baseUrl.getBaseUrlHttpUrl() == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl.getBaseUrlString())
                    .client(okHttpClient)
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))//适配器
                    .addConverterFactory(factory)//转换层
                    .build();
        } else if ((baseUrl.getBaseUrlString() == null && baseUrl.getBaseUrlHttpUrl() != null)) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl.getBaseUrlHttpUrl())
                    .client(okHttpClient)
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))//适配器
                    .addConverterFactory(factory)//转换层
                    .build();
        } else {
            retrofit = null;
        }
        if (BuildConfig.DEBUG) Log.d(TAG, "新建Retrofit -----------------");
        retrofitMap.put(okHttpClientMap.get(baseUrl), retrofit);
        return retrofit;
    }

}
